/* ~.~ *-c-*
 *
 * Copyright (c) 2019, Jacky Quene <qdjiangzhikun@163.com>
 * 2019年 01月 31日 星期四 14:33:41 CST
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */
#ifndef _PROTOL_MACHINE_H_
#define _PROTOL_MACHINE_H_

//#include "multi_timer.h"
#include "BasicInclude.h"

#include <stdint.h>

#define MAX_PROTOLELEMENT_LENGTH    128     //单个协议元素最大长度
#define MAX_PROTOLPACKAGE_LENGTH    2048    //单包协议数据最大长度

#define MAX_PROTOLELEMENT_COUNT     32      //一个协议最多可以由32个协议元素组成

typedef enum _ProtolElementType {
    eProtolElementConstant,		//恒定类型，如header    ender
    eProtolElementLength,		//长度类型，用来只指示数据包的长度
    eProtolElementData,			//数据类型，用来指示该协议元素是数据类型
    eProtolElementCommand,		//命令类型，用来指示该协议元素是命令字类型
    eProtolElementNormal		//通用类型，除了上面特殊类型外的普通数据类型
} ProtolElementType;

typedef enum _ProtolElementStatus {
    eProtolElementError,
    eProtolElementContinue,
    eProtolElementDone
} ProtolElementStatus;

typedef int (*Cmd_callback)(void *content, int data_length);

typedef struct _command_info {
	int u32CommandNum;
	Cmd_callback tCommandCallback;
} CommandInfo;

typedef struct _ProtolElement {
  uint16_t u16ProtolElementLength;
  ProtolElementType tProtolElementType;
  uint8_t ProtolElementContent[128];
} ProtolElement;

#define MAX_COMMAND_CNT	32
#define ERR_CMDSET_FULL -1

typedef struct _ProtolMachine
{
	bool bLengthIsDataOnly;

	//整包数据
	uint8_t u8aProtolPackageContent[MAX_PROTOLPACKAGE_LENGTH];
	uint16_t u16TotalLength;            //整包数据总长度
	uint16_t u16TotalCount;             //整包数据总长度计数器
	uint16_t u16SubLength;              //单个协议元素总长度
	uint16_t u16SubCount;               //子计数器，单个协议元素长度计数器

	ProtolElement sProtolElementSets[MAX_PROTOLELEMENT_COUNT];  //协议元素集合
	uint8_t u8ProtolElementCount;       //协议元素计数器
	uint8_t u8ProtolElementLength;      //这个协议里面有多少个协议元素

	uint16_t u16DataIndex;				//数据段在帧集合中的位置
	uint16_t u16CommandIndex;			//命令字段在帧集合中的位置
	
	CommandInfo cmdInfos[MAX_COMMAND_CNT];				//保存命令执行信息，最多支持32条命令
	
} ProtolMachine;


bool InitProtolMachine(ProtolMachine **pProtolMach);
void ResetProtolMachine(ProtolMachine *pProtolMach);

//增加一个元素到协议集合中
bool AddProtolElement(ProtolMachine *pProtolMach, ProtolElement *pProtolElem);

//协议解码器
bool ProtolMachineDecode(ProtolMachine *pProtolMach, uint8_t *data, uint16_t length,
		uint8_t *data_vld, uint16_t *length_content, uint8_t *package_cnt);

void SetDataOnlyFlag(ProtolMachine *pProtolMach, bool flag);
ProtolElementStatus ProtolMachineElementDecode(ProtolMachine *pProtolMach, uint8_t *data, uint16_t length,
		uint8_t *data_vld, uint16_t *length_content, uint8_t *package_cnt);


//注册命令号以及该命令的处理函数
int RegistCommandInfo(ProtolMachine *pProtolMach, CommandInfo cmd_info);

//注册一组命令
int RegistCommandInfoArray(ProtolMachine *pack_info, CommandInfo *cmd_info, int cmd_cnt);

int GetCommandIndex(int cmd_no, CommandInfo *cmd_infos);
#endif
